import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Reflector } from '@nestjs/core';

import { OperlogConfig } from '../decorators/operlog.decorator';
import { OperlogService } from 'src/module/monitor/operlog/operlog.service';

@Injectable()
export class OperlogInterceptor implements NestInterceptor {
  private readonly reflector = new Reflector();

  constructor(readonly logService: OperlogService) {}

  // 格式化错误信息
  private formatErrorMsg(error: any): string {
    if (typeof error === 'string') {
      return error;
    }
    if (error && typeof error === 'object') {
      // 如果是 BadRequestException 等抛出的错误
      if (error.message) {
        return error.message;
      }
      // 如果是其他对象类型的错误
      return JSON.stringify(error);
    }
    return '未知错误';
  }

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const { summary } = this.reflector.getAllAndOverride(`swagger/apiOperation`, [context.getHandler()]);
    const logConfig: OperlogConfig = this.reflector.get('operlog', context.getHandler());
    const handlerName = context.getHandler().name;
    const now = Date.now();

    return next
      .handle()
      .pipe(
        map((resultData) => {
          const costTime = Date.now() - now;
          if (resultData.code === 200) {
            this.logService.logAction({ 
              costTime, 
              resultData, 
              handlerName, 
              title: summary, 
              businessType: logConfig?.businessType 
            });
          } else {
            // 业务错误
            this.logService.logAction({ 
              costTime, 
              errorMsg: this.formatErrorMsg(resultData.msg), 
              handlerName, 
              title: summary, 
              businessType: logConfig?.businessType 
            });
          }
          return resultData;
        }),
      )
      .pipe(
        catchError((err) => {
          const costTime = Date.now() - now;
          this.logService.logAction({ 
            costTime, 
            errorMsg: this.formatErrorMsg(err.response), 
            handlerName, 
            title: summary, 
            businessType: logConfig?.businessType 
          });
          return throwError(() => err);
        }),
      );
  }
}
